package com.fili.core;

import java.util.ArrayList;
import java.lang.reflect.Method;
import java.io.*;

/**
 * Created by Claudiu-Florin FILIMON
 * Date: Oct 5, 2006
 * Time: 12:42:05 PM
 * Revision: 0
 */
public class Parser
{
    public static final String RESERVED_BEGIN_PARAM = "BEGIN_PARAM";
    public static final String RESERVED_END_PARAM = "END_PARAM";
    public static final String RESERVED_BEGIN_OPTION = "BEGIN_OPTION";
    public static final String RESERVED_END_OPTION = "END_OPTION";
    public static final String RESERVED_BEGIN_COMMAND = "BEGIN_COMMAND";
    public static final String RESERVED_END_COMMAND = "END_COMMAND";

    public static final int RESERVED_NOT = 0;
    public static final int RESERVED_BEGIN_PARAM_ID = 1;
    public static final int RESERVED_END_PARAM_ID = 2;
    public static final int RESERVED_BEGIN_OPTION_ID = 3;
    public static final int RESERVED_END_OPTION_ID = 4;
    public static final int RESERVED_BEGIN_COMMAND_ID = 5;
    public static final int RESERVED_END_COMMAND_ID = 6;

    public static final Object reserved[][] = new Object[][]{
            {RESERVED_BEGIN_PARAM, new Integer(RESERVED_BEGIN_PARAM_ID)},
            {RESERVED_BEGIN_OPTION, new Integer(RESERVED_BEGIN_OPTION_ID)},
            {RESERVED_BEGIN_COMMAND, new Integer(RESERVED_BEGIN_COMMAND_ID)},
            {RESERVED_END_PARAM, new Integer(RESERVED_END_PARAM_ID)},
            {RESERVED_END_OPTION, new Integer(RESERVED_END_OPTION_ID)},
            {RESERVED_END_COMMAND, new Integer(RESERVED_END_COMMAND_ID)}
    };

    private String error;
    private int lineCount;
    private RandomAccessFile raf;
    private BatchJob batchJob;


    public BatchJob getBatchJob()
    {
        return batchJob;
    }

    public Parser()
    {
        batchJob = new BatchJob("Test");
    }


    public boolean parseFile(String fileName) throws Exception
    {
        raf = new RandomAccessFile(fileName, "r");
        lineCount = 0;

        while (raf.getFilePointer() < raf.length())
            parseBlock();

        raf.close();
        return true;
    }

    private String readLine() throws Exception
    {
        String s;
        do
        {
            s = raf.readLine();
            lineCount++;
            if (s != null)
            {
                s = s.trim();
            }
        }
        while ((s != null) && (s.length() == 0));

        return s;
    }

    private int getReserved(String s)
    {
        if (s == null)
            return RESERVED_NOT;

        s = s.toUpperCase().trim();

        for (int i=0;i<reserved.length;i++)
            if (s.startsWith((String) reserved[i][0]))
                return ((Integer) reserved[i][1]).intValue();

        return RESERVED_NOT;
    }

    private boolean parseBlock() throws Exception
    {
        String s = readLine();

        if (s == null)
            //no more blocks
            return true;

        int id = getReserved(s);

        switch (id)
        {
            case RESERVED_BEGIN_PARAM_ID:
            case RESERVED_BEGIN_OPTION_ID:
                return block_param(s);
            case RESERVED_BEGIN_COMMAND_ID:
                return block_command(s);
        }

        throw new ParserException("Unknown command in line " + lineCount);
    }

    private boolean block_param(String s) throws Exception
    {
        String p[] = s.split("\\s+");   //split ignoring whitespace

        if (p.length != 2)
            throw new ParserException("Invalid syntax in line " + lineCount);

        if (findParam(p[1]) >= 0)
            throw new ParserException("Param already defined in line " + lineCount);

        CompileParam param = new CompileParam(p[1]);
        batchJob.params.add(param);

        param.setExclusive(getReserved(s) == RESERVED_BEGIN_OPTION_ID);
        do
        {
            s = readLine();

            int id = getReserved(s);
            if (id != RESERVED_NOT)
            {
                if ((param.isExclusive() && (id == RESERVED_END_OPTION_ID)) || ((!param.isExclusive() && (id == RESERVED_END_PARAM_ID))))
                    return true;
                throw new ParserException("Invalid syntax in line " + lineCount);
            }
            param.addValue(s);
        }
        while (s != null);

        if (param.isExclusive())
            throw new ParserException("Expecting END_OPTION in line " + lineCount);
        else
            throw new ParserException("Expecting END_PARAM in line " + lineCount);
    }

    private boolean block_command(String s) throws Exception
    {
        String p[] = s.split("\\s+");   //split ignoring whitespace

        if (p.length != 1)
            throw new ParserException("Invalid syntax in line " + lineCount);

        do
        {
            s = readLine();

            int id = getReserved(s);
            if (id != RESERVED_NOT)
            {
                if (id == RESERVED_END_COMMAND_ID)
                    return true;
                throw new ParserException("Invalid syntax in line " + lineCount);
            }
            batchJob.commands.add(s);
        }
        while (s != null);

        throw new ParserException("Expecting END_COMMAND in line " + lineCount);
    }

    private int findParam(String s)
    {
        for (int i = 0; i < batchJob.params.size(); i++)
            if (s.equals(((CompileParam)(batchJob.params.get(i))).getName()))
                return i;

        return -1;
    }
}
